//udp_client.cc
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include<stdlib.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>

const int BUFFER_SIZE = 1024; //读写缓冲区大小

void Usage(std::string proc)//打印使用说明
{
    std::cout << "Usage: \n\t" << proc << " server_ip, server_port" << std::endl;
}

//我们将来是这样启动程序的:/UdpClient server_ip server_port
int main(int argc, char* argv[])
{
    // 获取命令行参数
    if (argc != 3)//如果不是3个参数
     {
        Usage(argv[0]);//打印使用说明
        exit(0);
    }
    std::cout << "Hello UdpClient" << std::endl;

    //1. 创建套接字,打开网络文件
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) 
    {
        std::cerr << "socket error: " << errno << std::endl;
        exit(1);
    }

    //客户端进行网络通信必须要有IP地址和端口,但不需要显式绑定指定的端口
    //由系统随机分配,防止端口被占用

    //2. 使用服务
    // 服务端地址结构体
    struct sockaddr_in server;
    server.sin_family = AF_INET;                   // 协议家族
    server.sin_addr.s_addr = inet_addr(argv[1]);   // IP地址-需要将字符串IP转为整数IP
    server.sin_port = htons(atoi(argv[2]));        // 端口号-先将字符串->整数(主机序)->网络字节序

    bool quit = false;
    while (!quit) 
    {
        char msg[1024];
        std::cout << "MyShell: ";
        fgets(msg, sizeof(msg), stdin);//从键盘上读取内容
        //把msg的内容发送数据给服务器
        sendto(sock, msg, strlen(msg), 0, (struct sockaddr*)&server, sizeof(server));

        struct sockaddr_in tmp; //tmp仅用于传参,无实际意义
        socklen_t len = sizeof(tmp);
        char buf[BUFFER_SIZE] = { 0 };
        //接收客户端传回来的数据
        ssize_t cnt = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&tmp, &len);
        if (cnt > 0) 
        {
            buf[cnt] = 0;//置\0
            std::cout << "server # " << std::endl << buf << std::endl;
        }
        else 
        {
            std::cerr << "recvfrom error" << std::endl;
        }
    }
    return 0;
}
